package com.ihr360.mail.service.impl;

import com.google.common.base.Charsets;
import com.google.common.base.Strings;
import com.ihr360.commons.exception.Ihr360Exception;
import com.ihr360.commons.lang.CollectionUtils;
import com.ihr360.commons.lang.StringUtils;
import com.ihr360.mail.dao.MailSettingDao;
import com.ihr360.mail.dto.MailSettingDto;
import com.ihr360.mail.service.MailSettingService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.mail.AuthenticationFailedException;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.NoSuchProviderException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.List;
import java.util.Properties;

/**
 * @author
 * @Date
 */
@Service
public class MailSettingServiceImpl implements MailSettingService {

    Logger logger = LoggerFactory.getLogger(MailSettingServiceImpl.class);

    @Autowired
    private MailSettingDao mailSettingDao;

    private Session emailSession;
    private Transport emailTransport;

    /**
     * 删除邮箱设置信息
     *
     * @param companyId
     * @param id
     * @return
     */
    @Override
    @Transactional
    public Boolean deleteMail(String companyId, String id) {
        if (StringUtils.isBlank(id) || StringUtils.isBlank(companyId)) {
            return false;
        }
        MailSettingDto sendMail = mailSettingDao.findOne(id);
        if (sendMail == null || !companyId.equals(sendMail.getCompanyId())) {
            throw new Ihr360Exception("irs.biz.exception.error714", "未找到发信箱信息");
        }
        mailSettingDao.delete(id);
        return true;
    }

    /**
     * 获取邮箱设置信息
     *
     * @param companyId
     * @return
     */
    @Override
    public MailSettingDto findMailDetail(String companyId) {
        List<MailSettingDto> mailSettingDtos = mailSettingDao.findByCompanyId(companyId);
        if (CollectionUtils.isNotEmpty(mailSettingDtos)) {
            return mailSettingDao.findByCompanyId(companyId).get(0);
        } else {
            return null;
        }
    }

    /**
     * 直接保存邮箱设置信息(不校验)
     *
     * @param sendMessageEmailSetting
     * @return
     */
    @Override
    @Transactional
    public MailSettingDto saveMail(String companyId, MailSettingDto sendMessageEmailSetting) {
        mailSettingDao.deleteByCompanyId(companyId);
        sendMessageEmailSetting.setCompanyId(companyId);
        sendMessageEmailSetting = mailSettingDao.save(sendMessageEmailSetting);
        return sendMessageEmailSetting;
    }

    @Override
    public boolean sendMail(String companyId, String emailContent, String recipient, String subject) {
        List<MailSettingDto> mailSettingDtoList = mailSettingDao.findByCompanyId(companyId);
        if (CollectionUtils.isEmpty(mailSettingDtoList)) {
            logger.error("您的公司还没有设置工资条发送邮箱，请在“企业设置”中进行配置！");
            return false;
        }
        MailSettingDto mailSettingDto = mailSettingDtoList.get(0);
        String port = mailSettingDto.getMailSmtpPort();
        String emailAddress = mailSettingDto.getMailAddress();
        String emailPassword = mailSettingDto.getMailPassword();
        String emailSmtpServer = mailSettingDto.getMailSmtp();
        emailSession = handleProperties(new Properties(), mailSettingDto.getMailIsSSL(), emailSmtpServer, port);
        try {
            emailTransport = emailSession.getTransport(mailSettingDto.getMailIsSSL() ? "smtps" : "smtp");
            emailTransport.connect(emailSmtpServer, emailAddress, emailPassword);
            sendEmail(emailAddress, emailPassword, emailSmtpServer, new InternetAddress[]{new InternetAddress(recipient)}, subject, emailContent);
        } catch (NoSuchProviderException e) {
            logger.error(emailAddress + "----" + emailPassword + "----" + emailSmtpServer + "----" + mailSettingDto.getCompanyId() + "----" + e.getMessage());
            throw new Ihr360Exception("irs.biz.exception.error712", "邮箱登录名或密码错误");
        } catch (MessagingException e) {
            logger.error(emailAddress + "----" + emailPassword + "----" + emailSmtpServer + "----" + mailSettingDto.getCompanyId() + "----" + e.getMessage());
            throw new Ihr360Exception("irs.biz.exception.error713", "发信箱服务器 " + emailSmtpServer + " 连接失败", new Object[]{emailSmtpServer});
        } catch (Exception e) {
            logger.error("Encoding error: {}.", e.getMessage());
        } finally {
            if (emailTransport != null) {
                try {
                    emailTransport.close();
                } catch (MessagingException e) {
                    e.printStackTrace();
                }
            }
        }
        return true;
    }

    /**
     * 测试连接并保存
     *
     * @param sendMessageEmailSetting
     * @return
     */
    @Override
    @Transactional
    public MailSettingDto testConnect(String companyId, MailSettingDto sendMessageEmailSetting) {
        if (!this.commonConnect(sendMessageEmailSetting)) {
            return sendMessageEmailSetting;
        }
        //sendMessageEmailSetting.setIsConnect(true);
        mailSettingDao.deleteByCompanyId(companyId);
        sendMessageEmailSetting = mailSettingDao.save(sendMessageEmailSetting);
        return sendMessageEmailSetting;
    }

    private Boolean commonConnect(MailSettingDto sendMessageEmailSetting) {
        String port = sendMessageEmailSetting.getMailSmtpPort();
        String emailAddress = sendMessageEmailSetting.getMailAddress();
        String emailPassword = sendMessageEmailSetting.getMailPassword();
        String emailSmtpServer = sendMessageEmailSetting.getMailSmtp();
        Properties prop = new Properties();
        Session session = this.handleProperties(prop, sendMessageEmailSetting.getMailIsSSL(), emailSmtpServer, port);
        Transport transport = null;
        try {
            transport = session.getTransport(sendMessageEmailSetting.getMailIsSSL() ? "smtps" : "smtp");
            transport.connect(emailSmtpServer, emailAddress, emailPassword);
        } catch (AuthenticationFailedException e) {
            logger.error(emailAddress + "----" + emailPassword + "----" + emailSmtpServer + "----" + sendMessageEmailSetting.getCompanyId() + "----" + e.getMessage());
            throw new Ihr360Exception("irs.biz.exception.error712", "邮箱登录名或密码错误");
        } catch (Exception e) {
            logger.error(emailAddress + "----" + emailPassword + "----" + emailSmtpServer + "----" + sendMessageEmailSetting.getCompanyId() + "----" + e.getMessage());
            throw new Ihr360Exception("irs.biz.exception.error713", "发信箱服务器 " + emailSmtpServer + " 连接失败", new Object[]{emailSmtpServer});
        } finally {
            if (transport != null) {
                try {
                    transport.close();
                } catch (MessagingException e) {
                    e.printStackTrace();
                }
            }
        }
        return true;
    }

    private void sendEmail(String emailAddress, String emailPassword, String emailSmtpServer, InternetAddress[] to, String subject, String content) throws Exception {
        try {
            InternetAddress fromAddress = new InternetAddress(emailAddress);
            MimeMessage message = new MimeMessage(emailSession);
            message.setFrom(fromAddress);
            message.addRecipients(Message.RecipientType.TO, to);
            message.setSentDate(new Date());
            message.setSubject(MimeUtility.encodeText(subject, Charsets.UTF_8.toString(), "B"));

            MimeMultipart allPart = new MimeMultipart("mixed");
            // 创建邮件的各个 MimeBodyPart 部分
            MimeBodyPart body = createContent(content);
            allPart.addBodyPart(body);
            message.setContent(allPart);
            if (!emailTransport.isConnected()) {
                emailTransport.connect(emailSmtpServer, emailAddress, emailPassword);
            }
            emailTransport.sendMessage(message, message.getAllRecipients());
        } catch (UnsupportedEncodingException e) {
            logger.error("Encoding error: {}.", e.getMessage());
        }
    }

    /**
     * 根据传入的邮件正文body和文件路径创建图文并茂的正文部分
     */
    public MimeBodyPart createContent(String body)
            throws Exception {
        // 用于保存最终正文部分
        MimeBodyPart contentBody = new MimeBodyPart();
        // 用于组合文本和图片，"related"型的MimeMultipart对象
        MimeMultipart contentMulti = new MimeMultipart("related");
        // 正文的文本部分
        MimeBodyPart textBody = new MimeBodyPart();
        textBody.setContent(body, "text/html;charset=gbk");
        contentMulti.addBodyPart(textBody);

        /*Pattern pattern = Pattern.compile("(\"cid:)([a-zA-Z0-9-]*)(\")");
        Matcher matcher = pattern.matcher(body);
        while (matcher.find()) {
            // 正文的图片部分
            BinaryFile gridFSDBFile = binaryFileService.load(matcher.group(2));
            if (gridFSDBFile != null) {
                MimeBodyPart jpgBody = new MimeBodyPart();
                ByteArrayDataSource fds = new ByteArrayDataSource(gridFSDBFile.getInputStream(),
                        gridFSDBFile.getContentType() == null ? "application/octet-stream" : gridFSDBFile.getContentType());
                jpgBody.setDataHandler(new DataHandler(fds));
                jpgBody.setContentID(matcher.group(2));
                contentMulti.addBodyPart(jpgBody);
            }
        }*/

        // 将上面"related"型的 MimeMultipart 对象作为邮件的正文
        contentBody.setContent(contentMulti);
        return contentBody;
    }


    private Session handleProperties(Properties prop, boolean useSsl, String emailSmtpServer, String port) {
        if (Strings.isNullOrEmpty(port)) {
            port = useSsl ? "465" : "25";
        }
        if (useSsl) {
            prop.setProperty("mail.smtps.auth", "true");
            prop.setProperty("mail.smtps.host", emailSmtpServer);
            prop.setProperty("mail.smtps.port", port);
            prop.setProperty("mail.smtps.ssl.protocols", "TLSv1 TLSv1.1 TLSv1.2");
            prop.setProperty("mail.smtps.ssl.ciphersuites", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA TLS_RSA_WITH_AES_128_CBC_SHA TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA TLS_ECDH_RSA_WITH_AES_128_CBC_SHA TLS_DHE_RSA_WITH_AES_128_CBC_SHA TLS_DHE_DSS_WITH_AES_128_CBC_SHA TLS_ECDHE_ECDSA_WITH_RC4_128_SHA TLS_ECDHE_RSA_WITH_RC4_128_SHA SSL_RSA_WITH_RC4_128_SHA TLS_ECDH_ECDSA_WITH_RC4_128_SHA TLS_ECDH_RSA_WITH_RC4_128_SHA TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA SSL_RSA_WITH_3DES_EDE_CBC_SHA TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA SSL_RSA_WITH_RC4_128_MD5 TLS_EMPTY_RENEGOTIATION_INFO_SCSV");
            prop.setProperty("mail.smtps.connectiontimeout", "30000");
            prop.setProperty("mail.smtps.timeout", "30000");
        } else {
            prop.setProperty("mail.smtp.auth", "true");
            prop.setProperty("mail.smtp.host", emailSmtpServer);
            prop.setProperty("mail.smtp.port", port);
            prop.setProperty("mail.smtp.connectiontimeout", "30000");
            prop.setProperty("mail.smtp.timeout", "30000");
        }
        return Session.getInstance(prop);
    }


}

